package it.giuseppetrisciuoglio.lyrics.processor.artista;

import it.giuseppetrisciuoglio.lyrics.exception.ArtistaNotFoundException;
import it.giuseppetrisciuoglio.lyrics.persistence.entity.Album;
import it.giuseppetrisciuoglio.lyrics.persistence.entity.Artista;
import it.giuseppetrisciuoglio.lyrics.persistence.entity.MetaDataInfoArtista;
import it.giuseppetrisciuoglio.lyrics.persistence.repository.AlbumRepository;
import it.giuseppetrisciuoglio.lyrics.persistence.repository.ArtistaRepository;
import it.giuseppetrisciuoglio.lyrics.persistence.repository.MetaDataInfoArtistaRepository;
import it.giuseppetrisciuoglio.lyrics.processor.BaseProcessor;

import java.io.IOException;
import java.util.List;

import org.apache.camel.Body;
import org.apache.camel.EndpointInject;
import org.apache.camel.Exchange;
import org.apache.camel.ProducerTemplate;
import org.musicbrainz.android.api.MusicBrainz;
import org.musicbrainz.android.api.data.*;
import org.musicbrainz.android.api.webservice.MusicBrainzWebClient;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

@Service
public class ArtistaCreateProcessor extends BaseProcessor {

	@Autowired
	private ArtistaRepository artistaRepository;
	
	@Autowired
	private MetaDataInfoArtistaRepository metaDataInfoArtistaRepository;
	
	@Autowired
	private AlbumRepository albumRepository;
	
	@Autowired
	private ArtistaAdapter artistaAdapter;
	
	@Autowired
	@Value("${http.userAgent}")
	private String userAgent;
	
	@EndpointInject(ref="artistaCreatorJMS")
	private ProducerTemplate asyncProducerTemplate;
	
	private final transient Logger log = LoggerFactory.getLogger(getClass());
	
	private Artist searchArtistMusicBrainz(MusicBrainz client, String nomeArtista) throws IOException, ArtistaNotFoundException, InterruptedException {
		log.debug("searchArtistMusicBrainz(): client={}, nomeArtista={}", client, nomeArtista);
		Thread.sleep(5000);
		List<ArtistSearchResult> artistSearchResults =  client.searchArtist(nomeArtista);
		log.debug("create(): artistSearchResultSize={}", artistSearchResults.size());
		Artist artist = null;
		for (ArtistSearchResult artistSearchResult : artistSearchResults) {
			log.debug("create(): artistSearchResult={}", artistSearchResult.getScore() +" - "+ artistSearchResult.getName());
			if (artistSearchResult.getScore().equalsIgnoreCase("100")
					&& artistSearchResult.getName().equalsIgnoreCase(nomeArtista.trim())){
				log.debug("create(): artistSearchResult={}", artistSearchResult);
				String mbid = artistSearchResult.getMbid();
				Artista artistaDB = artistaRepository.findByMbid(mbid);
				if (artistaDB != null){
					log.debug("create(): artista già presente, artista={}", artistaDB);
					break;
				}
				artist = client.lookupArtist(mbid);
				break;
			}
		}
		if (artist == null){
			log.error("create(): artista '{}' non trovato.", nomeArtista);
			throw new ArtistaNotFoundException();
		}
		return artist;
	}
	
	private Artista converterAndSave(Artist artist) {
		Artista artista = artistaAdapter.convertMusicbrainzEntity(artist);
		return artistaRepository.save(artista);
	}
	
	private void saveMetaDataInfoArtista(Artist artist, Artista artista){
		List<MetaDataInfoArtista> metaDataInfoArtistas = artistaAdapter.convertMetaDataInfoArtistas(artist.getLinks(), artista);
		for (MetaDataInfoArtista metaDataInfoArtista : metaDataInfoArtistas) {
			metaDataInfoArtistaRepository.save(metaDataInfoArtista);
		}
	}
	
	private void saveAlbumInfo(MusicBrainz client, Artist artist, Artista artista) throws IOException{
		for (ReleaseGroupInfo releaseGroupInfo : artist.getReleaseGroups()) {
			List<ReleaseInfo> releaseInfos = client.browseReleases(releaseGroupInfo.getMbid());
			if (releaseInfos != null && !releaseInfos.isEmpty()){
				Release release = client.lookupRelease(releaseInfos.get(0).getReleaseMbid());
				if (release != null && release.getStatus() != null && release.getStatus().equals("Official")){
					Album album = artistaAdapter.convertReleaseToAlbum(release, artista);
					albumRepository.save(album);
				}
			}
		}
	}

	public void create(Exchange exchange, @Body String nomeArtista){
		log.debug("create(): exchange={}, nomeArtista={}", exchange, nomeArtista);	
		MusicBrainz musicBrainz = new MusicBrainzWebClient(userAgent);
		try {
			
			Artist artist = searchArtistMusicBrainz(musicBrainz, nomeArtista);
			Artista artista = converterAndSave(artist);
			saveMetaDataInfoArtista(artist, artista);
			saveAlbumInfo(musicBrainz, artist, artista);
			
			log.debug("create(): artistaId={} creato con sucesso.", artista.getId());
			log.debug("create(): artista '{}' creato con sucesso.", nomeArtista);
			
			sendMessageToLyricsDownloadProcessor(artista.getId());

		} catch (ArtistaNotFoundException e) {
			log.error("create(): artista non trovato, nomeArtista={}", nomeArtista);	
		} catch (IOException e) {
			log.error("findArtistaOnMusicbrainz(): timout={}", e.getMessage());
			asyncManageTimeOut(nomeArtista);
		} catch (Exception e) {
			log.error("findArtistaOnMusicbrainz(): exeption={}", e.getMessage());
			log.debug("findArtistaOnMusicbrainz(): exeption={}", e);
		}
	}
	
	private void asyncManageTimeOut(String nomeArtista){
		log.debug("asyncManageTimeOut(): nomeArtista={}", nomeArtista);
		try {
			asyncProducerTemplate.start();
			asyncProducerTemplate.sendBody(nomeArtista);
		} catch (Exception e) {
			log.error("asyncManageTimeOut(): exception={}", e);
			throw new RuntimeException(e);
		}
	}
	
}